package com.kt.NetworkModel.net.interceptor

import com.kt.NetworkModel.utils.MLog
import okhttp3.*
import okio.Buffer
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit
import java.util.logging.Level
import java.util.logging.Logger


/**
 * Administrator
 * 2022/7/7
 * desc：
 */
class LogInterceptor : Interceptor {
    private val logBody = true
    private val logHeaders = true
    private lateinit var logger: Logger
    private val UTF8 = Charset.forName("UTF-8")
    private val colorLevel = Level.INFO
    private var tag = ""
    private var getHttpUrl: String = ""

    constructor(tag: String) {
        this.tag = tag
        logger = Logger.getLogger(tag)

    }

    private fun log(msg: String) {
        logger.log(colorLevel, msg)
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        //发送请求之前添加  head  头部
        val request = chain.request().newBuilder()
            .build()
        //请求日志拦截
        logForRequest(request, chain.connection())
        //执行请求，计算请求时间
        val startNs = System.nanoTime()
        var response: Response
        try {
            response = chain.proceed(request)
        } catch (e: Exception) {
            log("<-- HTTP FAILED: $e")
            throw e
        }
        val tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs)
        //响应日志拦截
        return logForResponse(response, tookMs)
    }

    @Throws(IOException::class)
    private fun logForRequest(request: Request, connection: Connection?) {
        val requestBody = request.body
        val hasRequestBody = requestBody != null
        val protocol = if (connection != null) connection.protocol() else Protocol.HTTP_1_1
        try {
            val requestStartMessage = "--> " + request.method + ' ' + request.url + ' ' + protocol
            log(requestStartMessage)
            if (logHeaders) {
                if (hasRequestBody) {
                    // Request body headers are only present when installed as a network interceptor. Force
                    // them to be included (when available) so there values are known.
                    if (requestBody!!.contentType() != null) {
                        log("\tContent-Type: " + requestBody.contentType())
                    }
                    if (requestBody.contentLength() != -1L) {
                        log("\tContent-Length: " + requestBody.contentLength())
                    }
                }
                val headers = request.headers
                for (i in 0 until headers.size) {
                    val name: String = headers.name(i)
                    // Skip headers from the request body as they are explicitly logged above.
                    if (!"Content-Type".equals(name, ignoreCase = true) && !"Content-Length".equals(name, ignoreCase = true)) {
                        log("\t" + name + ": " + headers.value(i))
                    }
                }
                log(" ")
                if (logBody && hasRequestBody) {
                    if (isPlaintext(requestBody?.contentType())) {
                        bodyToString(request)
                    } else {
                        log("\tbody: maybe [binary body], omitted!")
                    }
                }
            }
        } catch (e: Exception) {
            MLog.d(e.message)
        } finally {
            log("--> END " + request.method);
        }

    }

    private fun bodyToString(request: Request) {
        try {
            val copy = request.newBuilder().build()
            val body = copy.body ?: return
            val buffer = Buffer()
            body.writeTo(buffer)
            val charset: Charset = getCharset(body.contentType())
            log("\tbody:" + buffer.readString(charset))
        } catch (e: java.lang.Exception) {
            MLog.d(e.message)
        }
    }

    private fun logForResponse(response: Response, tookMs: Long): Response {
        val builder = response.newBuilder()
        val clone = builder.build()
        var responseBody = clone.body
        try {
            log("<-- " + clone.code + ' ' + clone.message + ' ' + clone.request.url + " (" + tookMs + "ms）")
            if (logHeaders) {
                val headers = clone.headers
                for (i in 0 until headers.size) {
                    log("\t" + headers.name(i) + ": " + headers.value(i))
                }
                log(" ")
                if (responseBody == null) return response
                if (isPlaintext(responseBody.contentType())) {
                    val bytes: ByteArray = toByteArray(responseBody.byteStream())
                    val contentType = responseBody.contentType()
                    val body = String(bytes, getCharset(contentType))
                    log("\tbody:$body")
                    val s = clone.request.url.toUrl().toString()
                    responseBody = ResponseBody.create(responseBody.contentType(), bytes)
                    return response.newBuilder().body(responseBody).build()
                } else {
                    log("\tbody: maybe [binary body], omitted!")
                }
            }
        } catch (e: Exception) {
            MLog.d(e.message)
        } finally {
            log("<-- END HTTP");
        }
        return response
    }

    private fun getCharset(contentType: MediaType?): Charset {
        return if (contentType == null) UTF8 else contentType.charset(UTF8)!!
    }

    @Throws(IOException::class)
    fun toByteArray(inputStream: InputStream): ByteArray {
        val buffer = ByteArray(1024 * 4)
        val outputStream = ByteArrayOutputStream()
        var bytesRead: Int
        while (inputStream.read(buffer).also { bytesRead = it } != -1) {
            outputStream.write(buffer, 0, bytesRead)
        }
        return outputStream.toByteArray()
    }

    private fun isPlaintext(mediaType: MediaType?): Boolean {
        if (mediaType == null) return false
        if (mediaType.type == "text") {
            return true
        }
        var subtype = mediaType.subtype
        subtype = subtype.toLowerCase()
        if (subtype.contains("x-www-form-urlencoded") || subtype.contains("json") || subtype.contains("xml") || subtype.contains("html"))
            return true
        return false
    }

}